package online.inote.naruto.utils;

import online.inote.naruto.annotation.Priority;
import online.inote.naruto.exception.ClassLoaderException;

import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;

/**
 * @description Class Loader(implemented the SPI mechanism)
 * @author gaopengsui@creditease.cn
 * @date 2021/10/26 11:21 下午
 */
public class ClassLoader {

  public static <T> T load(Class<T> clazz) {
    return ClassLoader.load(clazz, ClassLoader.class.getClassLoader());
  }

  public static <T> List<T> loadAll(Class<T> clazz, java.lang.ClassLoader classLoader) {
    List<T> list = new ArrayList<>();
    executeLoad(clazz, classLoader).forEach(loader -> list.add(loader));
    return list;
  }

  public static <T> T load(Class<T> clazz, java.lang.ClassLoader classLoader) {
    T service = null;
    int highestPriority = Priority.DEFAULT_PRIORITY;

    for (T loader : executeLoad(clazz, classLoader)) {
      final Priority priority = loader.getClass().getAnnotation(Priority.class);
      if (service == null || priority.value() < highestPriority) {
        service = loader;
        highestPriority = priority.value();
      }
    }

    return service;
  }

  public static <T> ServiceLoader<T> executeLoad(
      Class<T> clazz, java.lang.ClassLoader classLoader) {
    final ServiceLoader<T> loaders = ServiceLoader.load(clazz, classLoader);

    if (loaders == null) {
      throw new ClassLoaderException();
    }

    return loaders;
  }
}
